﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EsoLib
{
    public class StringNumerologyExplain
    {
        public static List<KeyValuePair<int, char>?> EngCharacters;
        public static List<KeyValuePair<int, char>?> RusCharacters;

        public static List<Meaning> Meanings; 

        static StringNumerologyExplain()
        {
            EngCharacters = new List<KeyValuePair<int, char>?>();
            RusCharacters = new List<KeyValuePair<int, char>?>();

            const char firstEng = 'a';
            const char lastEng = 'z';
            const char firstRus = 'а';
            const char lastRus = 'я';

            //filling english
            var eng = firstEng;
            var ind = 1;
            while (eng <= lastEng)
            {
                EngCharacters.Add(new KeyValuePair<int, char>(ind, eng));
                eng++;
                ind++;
                if (ind > 9)
                    ind = 1;
            }

            //filling russian
            var rus = firstRus;
            ind = 1;
            while (rus <= lastRus)
            {
                RusCharacters.Add(new KeyValuePair<int, char>(ind, rus));
                rus++;
                ind++;
                if (ind > 9)
                    ind = 1;
            }

            Meanings = new List<Meaning>();
            Meanings.Add(new Meaning(0, "Акцент", "акцент на предыдущем значении"));
            Meanings.Add(new Meaning(1, "Судьба", "От тебя ничего не зависит, все уже решено. Расслабься и плыви по течению"));
            Meanings.Add(new Meaning(2, "Ты прав", "Верно мыслишь, сука"));
            Meanings.Add(new Meaning(3, "Потери времени", "Не надейся на скорый результат"));
            Meanings.Add(new Meaning(4, "Все хорошо", "Не факт, что дешево, не факт, что так, как ты задумал. Но для тебя в итоге будет хорошо"));
            Meanings.Add(new Meaning(5, "Неосведомленность", "Ты не знаешь, как оно будет, не предполагай"));
            Meanings.Add(new Meaning(6, "Не то, что надо", "Ищи рядом. Дело - дрянь"));
            Meanings.Add(new Meaning(7, "Комфорт", "Не факт, что дешево, но комфортно, блеать"));
            Meanings.Add(new Meaning(8, "Путь", "Это нужно пройти"));
            Meanings.Add(new Meaning(9, "Идеально", "Идеальное решение, идеальный вкус - все охуенно"));
        }

        public static List<int> CheckName(string name)
        {
            var result = new List<int>();
            name = name.ToLower();

            foreach (var nchar in name)
            {
                var ind = CheckChar(nchar);
                if (ind != null)
                    result.Add((int) ind);
                else
                    result.Add(0);
            }

            return result;
        }
        private static int? CheckChar(char nchar)
        {
            var eng = EngCharacters.FirstOrDefault(p => p != null && p.Value.Value == nchar);
            if (eng != null)
                return eng.Value.Key;
            var rus = RusCharacters.FirstOrDefault(p => p != null && p.Value.Value == nchar);
            if (rus != null)
                return rus.Value.Key;

            var str = string.Empty + nchar;
            int ind;
            if (int.TryParse(str, out ind))
                return ind;

            return null;
        }
        public static int DigitsResult(int source)
        {
            var result = 0;

            var str = source.ToString();
            foreach (var s in str)
            {
                var st = string.Empty + s;
                var i = Convert.ToInt32(st);
                result += i;
            }

            if (result > 9)
                return DigitsResult(result);

            return result;
        }

        public static string ExplainString(string source)
        {
            var dres = CheckName(source);
            var res = DigitsResult(dres.Sum());
            return ExplainMe(dres, res, source);
        }

        public static string ExplainMe(List<int> digits, int result, string source)
        {
            var res = new StringBuilder();
            res.AppendLine(source);

            var rmeaning = Meanings.FirstOrDefault(p => p.Key == result);
            if (rmeaning != null)
            {
                res.AppendFormat("Результирующая (итог):\r\n");
                res.AppendFormat("{0}: {1}. {2}\r\n", rmeaning.Key, rmeaning.ShortInfo, rmeaning.Explanation);
                res.AppendLine();
            }

            var mres = new List<Meaning>();
            foreach (var digit in digits)
            {
                var meaning = Meanings.FirstOrDefault(p => p.Key == digit);
                if (meaning != null)
                    mres.Add(meaning);
            }

            for (int i = 0; i < mres.Count; i++)
            {
                var meaning = mres[i];
                if (meaning.Key == 0)
                    continue;

                var isAccent = false;
                if (i + 1 < mres.Count)
                    if (mres[i + 1].Key == 0)
                        isAccent = true;

                string x = string.Empty;
                if (source.Length > i)
                    x += source[i];

                res.AppendFormat("{0}({1}): ", meaning.Key, x);

                if (isAccent)
                    res.AppendFormat("Акцент!!!: ");

                res.AppendFormat("{0}. {1}\r\n", meaning.ShortInfo, meaning.Explanation);
            }

            return res.ToString();
        }
    }

    public class Meaning
    {
        public int Key;
        public string ShortInfo;
        public string Explanation;

        public Meaning(int key, string shortInfo, string explanation)
        {
            Key = key;
            ShortInfo = shortInfo;
            Explanation = explanation;
        }
    }
}
